// dbOperation
// 数据库操作单元

package main

import (
	"fmt"
	"server/src/common"
	"time"

	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"

	"server/src/gps"
	"server/src/protocol808"
	//"smartu365.com/protocol808"
)

// DBOperation 数据库操作类
type DBOperation struct {
	session *mgo.Session
	dbName  string
	cfg     *Config
	//gpsConvert gps.GPS //GPS坐标系统转换
}

const (
	//CollectionRawDatas              string = "rawdatas"              //原始数据表
	//CollectionRawDatasLast          string = "rawdataslast"          //最新的原始数据表
	CollectionRawDatasLast          string = "rawdataslast2503201619" //最新的原始数据表
	CollectionReceivers             string = "receivers"              //接收器基本信息表
	CollectionSensors               string = "sensors"                //传感器基本信息表
	CollectionTires                 string = "tires"                  //轮胎基本信息表
	CollectionPositions             string = "positions"              //位置信息表
	CollectionTrackDates            string = "trackdates"             //轨迹日期表
	CollectionLastStatuses          string = "laststatuses"           //最新状态表
	CollectionMileageStatistics     string = "mileagestatistics"      //里程统计表
	CollectionTireRawDatas          string = "tirerawdatas"           //胎温胎压原始数据表
	CollectionTireRawDatasLast      string = "tirerawdataslast"       //最新胎温胎压原始数据表
	CollectionTireDatas             string = "tiredatas"              //胎温胎压表
	CollectionRelations             string = "relations"              //关联关系表
	CollectionTireWarnings          string = "tirewarnings"           //轮胎报警信息表
	CollectionWarningTypes          string = "warningtypes"           //报警类别表
	CollectionTireWarningStatistics string = "tirewarningstatistics"  //轮胎报警信息统计表
	CollectionTimeStatistics        string = "timestatistics"         //工作时长统计表
	CollectionReceiverWarnings      string = "receiverwarnings"       // 设备报警表
)

// 原始数据状态
const (
	RawDataStatNew   int = 0 //新纪录
	RawDataStatRead  int = 1 //已被读取，但未处理
	RawDataStatDone  int = 2 //处理完成
	RawDataStatError int = 3 //异常
)

// 每次读入的最大纪录数
const MaxReadCount int = 50

// 胎温胎压纪录类别
const TireDataType string = "0900"

// NewDBOperation 创建新的数据库操作类
func NewDBOperation(cfg *Config) (*DBOperation, error) {
	zLog("数据库连接::", cfg.DBUrl, " 开始")
	session, err := mgo.Dial(cfg.DBUrl)
	if err != nil {
		zLog(nil, "数据库连接失败::", err.Error())
		return nil, err
	}
	if cfg.DBUser != "" && cfg.DBPwd != "" {
		err = session.Login(&mgo.Credential{
			Username: cfg.DBUser,
			Password: cfg.DBPwd,
		})
		if err != nil {
			zLog("数据库登录失败::", err.Error())
			return nil, err
		}
	}
	session.SetPoolLimit(10) //设置连接缓冲池的最大值

	dbo := DBOperation{session: session, dbName: cfg.DBName, cfg: cfg}

	return &dbo, nil
}

// Close the database
func (p *DBOperation) Close() {
	p.session.Close()
}

// 原始数据结构
type RawDataT struct {
	ID   bson.ObjectId `bson:"_id"`
	Imei string        `bson:"imei"`
	T    int64         `bson:"t"`
	Data string        `bson:"data"`
}

// 读取最新的1000条胎温胎压原始数据
func (p *DBOperation) GetNewRawDatas() ([]RawDataT, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRawDatasLast)
	var rds []RawDataT
	sortField := "t"
	if p.cfg.SortField == common.OrderDesc {
		sortField = "-t"
	}

	err := c.Find(bson.M{"dt": TireDataType, "stat": RawDataStatNew, "imei": "060422111864"}).Select(bson.M{"imei": 1, "t": 1, "data": 1}).
		Sort(sortField).Limit(MaxReadCount).All(&rds)

	return rds, err
}

// 更新温胎压原始数据为新纪录
func (p *DBOperation) UpdateNewRawDatas() {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRawDatasLast)
	_, _ = c.UpdateAll(bson.M{"dt": TireDataType, "stat": RawDataStatRead}, bson.M{"$set": bson.M{"stat": RawDataStatNew}})
}

// 删除最新原始数据记录
func (p *DBOperation) RemoveLastRawData(id bson.ObjectId) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRawDatasLast)
	_ = c.Remove(bson.M{"_id": id})
}

// 更新最新原始数据记录为已读取
func (p *DBOperation) UpdateLastRawData(id bson.ObjectId) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRawDatasLast)
	_ = c.Update(bson.M{"_id": id}, bson.M{"$set": bson.M{"stat": RawDataStatRead}})
}

// 轮胎原始数据表结构
type TireDataRawT struct {
	_id       bson.ObjectId            `bson:"_id"`   //_id
	RawId     bson.ObjectId            `bson:"rawid"` //原始数据表中的纪录标识
	Rid       string                   `bson:"rid"`   //接收器编号
	T         int64                    `bson:"t"`     //纪录的时间戳
	Date      int                      `bson:"date"`  //格式：YYMMDD
	Time      int                      `bson:"time"`  //格式：HHNNSS
	Latitude  float32                  `bson:"lat"`   //纬度
	Longitude float32                  `bson:"lng"`   //经度
	Count     int                      `bson:"count"` //轮胎数，仅仅是指本次数据包含的轮胎数，不是车的轮胎数
	Tires     []protocol808.TireData_t `bson:"tires"` //轮胎数据
}

// 胎温胎压数据表结构
type TireDataT struct {
	Rid         string  `bson:"rid"`    //接收器编号
	T           int64   `bson:"t"`      //纪录的时间戳
	Date        int     `bson:"date"`   //格式：YYMMDD
	Time        int     `bson:"time"`   //格式：HHNNSS
	CardId      int     `bson:"cardid"` //卡号
	SerialNum   int     `bson:"sn"`     //序号
	SensorId    string  `bson:"sid"`    //传感器ID
	Voltage     float32 `bson:"vol"`    //传感器电压
	Presure     float32 `bson:"pres"`   //气压，单位为Bar
	Temperature int     `bson:"temp"`   //温度
	Learned     int     `bson:"learned"`
}

// 轮胎报警表结构
type TireWarningT struct {
	Oid         bson.ObjectId `bson:"oid"`    //tirerawdatas中对应的纪录id，方便核对
	Rid         string        `bson:"rid"`    //接收器编号
	CardId      int           `bson:"cardid"` //卡号
	SerialNum   int           `bson:"sn"`     //序号
	SensorId    string        `bson:"sid"`    //传感器ID
	T           int64         `bson:"t"`      //纪录的时间戳
	Date        int           `bson:"date"`   //格式：YYMMDD
	Time        int           `bson:"time"`   //格式：HHNNSS
	Latitude    float32       `bson:"lat"`    //纬度
	Longitude   float32       `bson:"lng"`    //经度
	LatitudeB   float32       `bson:"latb"`   //纬度
	LongitudeB  float32       `bson:"lngb"`   //经度
	LatitudeG   float32       `bson:"latg"`   //纬度
	LongitudeG  float32       `bson:"lngg"`   //经度
	Voltage     float32       `bson:"vol"`    //传感器电压
	Presure     float32       `bson:"pres"`   //气压，单位为Bar
	Temperature int           `bson:"temp"`   //温度
	WarningType int           `bson:"wt"`     //报警类型
	Status      int           `bson:"stat"`   //状态
}

// 已经处理过的错误结构
type ProcessedError struct {
}

func (p ProcessedError) Error() string {
	return "本条原始数据已处理过，不保存"
}

// 保存轮胎原始数据
func (p *DBOperation) SaveTireRawData(tire *TireDataRawT) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireRawDatas)
	err := c.Find(bson.M{"rawid": tire.RawId}).Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		//这条数据已经处理过了，不保存
		err = ProcessedError{}
		return err //errors.New("本条原始数据已处理过，不保存")
	}

	cLast := s.DB(p.dbName).C(CollectionTireRawDatasLast)
	cLast.Insert(tire)

	return c.Insert(tire)
}

// 保存胎温胎压数据
func (p *DBOperation) SaveTireData(tireRawdata *TireDataRawT) {
	if len(tireRawdata.Tires) == 0 {
		return
	}

	s := p.session.Copy()
	defer s.Close()

	var tire TireDataT

	tire.Rid = tireRawdata.Rid
	tire.T = tireRawdata.T
	tire.Date = tireRawdata.Date
	tire.Time = tireRawdata.Time
	c := s.DB(p.dbName).C(CollectionTireDatas)

	p.ClearUnlearnedSensors(tire.Rid)

	for _, v := range tireRawdata.Tires {
		tire.CardId = v.CardId
		tire.SerialNum = v.SerialNum
		tire.SensorId = v.SensorId
		tire.Voltage = v.Voltage
		tire.Presure = v.Presure
		tire.Temperature = v.Temperature
		tire.Learned = v.Learned

		if v.Learned == 0 {
			if !(v.Presure == 0.0 && (v.Temperature == 0 || v.Temperature == 205)) {
				c.Insert(tire)
			}
			//保存传感器
			p.SaveSensor(tire.SensorId)
		}
		//更新最新状态表
		p.SaveLastTireData(&tire)
	}
}

func (p *DBOperation) ClearUnlearnedSensors(rid string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	return c.Update(bson.M{"rid": rid}, bson.M{"$pull": bson.M{"lp": bson.M{"learned": 1}}})
}

// 关联表
type RelationT struct {
	ReceiverId   string `bson:"rid"`
	SensorId     string `bson:"sid"`
	CardId       int    `bson:"cardid"`
	SerialNumber int    `bson:"sn"`
}

// 保存接收器与传感器的关系
func (p *DBOperation) SaveRelation(receiverid string, sensorid string, cardid int, sn int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRelations)
	var r RelationT

	err := c.Find(bson.M{"rid": receiverid, "cardid": cardid, "sn": sn}).Select(bson.M{"sid": 1, "_id": 0}).One(&r)
	if err != nil {
		//没有找到，则添加新纪录
		r.ReceiverId = receiverid
		r.SensorId = sensorid
		r.CardId = cardid
		r.SerialNumber = sn
		c.Insert(r)
	} else {
		if r.SensorId != sensorid {
			//两个传感器id不一样，说明接收器跟传感器的关联关系改变了
			c.Update(bson.M{"rid": receiverid, "cardid": cardid, "sn": sn}, bson.M{"$set": bson.M{"sid": sensorid}})
		}
	}
}

// 保存传感器
func (p *DBOperation) SaveSensor(sid string) {
	s := p.session.Copy()
	defer s.Close()

	var res interface{}
	c := s.DB(p.dbName).C(CollectionSensors)
	err := c.Find(bson.M{"sid": sid}).One(&res)
	if err != nil {
		c.Insert(bson.M{"sid": sid})
	}
}

// 最新胎温胎压数据结构
type LastTireDataT struct {
	SensorId     string  `bson:"sid"`
	LastTime     int64   `bson:"t"`      //最新时间
	CardId       int     `bson:"cardid"` //卡位号
	SerialNumber int     `bson:"sn"`     //卡位中的序号
	Voltage      float32 `bson:"vol"`    //传感器电压
	Presure      float32 `bson:"pres"`   //气压，单位为Bar
	Temperature  int     `bson:"temp"`   //温度
	Learned      int     `bson:"learned"`
}

type LastTireDatasT struct {
	LastTirePressure []LastTireDataT `bson:"lp"`
}

// 保存最新数据
func (p *DBOperation) SaveLastTireData(tireData *TireDataT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	var tires LastTireDatasT
	var lt LastTireDataT
	var newTime int64 = int64(tireData.Date*1000000) + int64(tireData.Time)

	lt.SensorId = tireData.SensorId
	lt.LastTime = newTime
	lt.CardId = tireData.CardId
	lt.SerialNumber = tireData.SerialNum
	lt.Voltage = tireData.Voltage
	lt.Presure = tireData.Presure
	lt.Temperature = tireData.Temperature
	lt.Learned = tireData.Learned

	err := c.Find(bson.M{"rid": tireData.Rid, "lp": bson.M{"$elemMatch": bson.M{"cardid": tireData.CardId,
		"sn": tireData.SerialNum, "learned": tireData.Learned}}}).
		Select(bson.M{"rid": 1, "lp.$": 1, "_id": 0}).
		One(&tires)
	if err != nil {
		//没有找到，插入新数据
		c.Upsert(bson.M{"rid": tireData.Rid}, bson.M{"$push": bson.M{"lp": lt}})
	} else {
		//有纪录，则比较一下时间，较新则更新
		if (tireData.Presure == 0.0 && tireData.Temperature == 0) || tireData.Temperature == 205 {
			return
		}
		c.Update(bson.M{"rid": tireData.Rid}, bson.M{"$pull": bson.M{"lp": bson.M{"cardid": tireData.CardId,
			"sn": tireData.SerialNum, "learned": tireData.Learned}}})
		c.Update(bson.M{"rid": tireData.Rid}, bson.M{"$push": bson.M{"lp": lt}})
	}
}

// 保存报警信息
func (p *DBOperation) SaveWarningInfor(warnData *TireWarningT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)
	var err error

	//获取最近一次未完成的报警纪录的时间
	//lastTime := p.GetLastWarning(warnData.Rid, warnData.SensorId, warnData.WarningType)
	lastTime := p.GetLastWarningByPosition(warnData.Rid, warnData.CardId, warnData.SerialNum, warnData.WarningType)
	if lastTime == 0 {
		//时间为0，说明以前的报警纪录已经处理完成，这是新的报警
		err = c.Insert(warnData)
	} else {
		interval := p.RewarnInterval(warnData.WarningType)
		if warnData.T-lastTime > int64(interval) {
			//把原来没有处理完成的报警设置为无效
			p.SetInvalidByPosition(warnData.Rid, warnData.CardId, warnData.SerialNum, warnData.WarningType)
			//插入新的报警信息
			err = c.Insert(warnData)
		}
	}
	if err != nil {
		zLog(err)
	}

	p.SaveReceiverWarning(warnData)

	p.SaveLastWarning(warnData)
}

type LastWarningT struct {
	T      int64  `bson:"t"`
	Type   int    `bson:"type"`
	Sid    string `bson:"sid"`
	Cardid int    `bson:"cardid"`
	Sn     int    `bson:"sn"`
	Stat   int    `bson:"stat"`
	Count  int    `bson:"count"`
}

type LastWarningsT struct {
	Lws []LastWarningT `bson:"lw"`
}

// 保存最新报警信息
func (p *DBOperation) SaveLastWarning(warnData *TireWarningT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	var res LastWarningsT

	//查询设备最新的同类报警
	//bsonQuery := bson.M{"rid": warnData.Rid, "lw": bson.M{"$elemMatch": bson.M{"sid": warnData.SensorId, "type": warnData.WarningType}}}
	//2020.06.01 改为根据轮位查询
	bsonQuery := bson.M{"rid": warnData.Rid, "lw": bson.M{"$elemMatch": bson.M{"cardid": warnData.CardId,
		"sn": warnData.SerialNum, "type": warnData.WarningType}}}
	err := c.Find(bsonQuery).Select(bson.M{"_id": 0, "lw.$": 1}).One(&res)

	if err == nil {
		//已有记录
		if len(res.Lws) > 0 {
			lw := &(res.Lws[0])
			if lw.Stat == 0 {
				//新纪录，即没有恢复正常，仍处于异常状态
				//累加异常次数即可，不做其它处理
				c.Update(bsonQuery, bson.M{"$inc": bson.M{"lw.$.count": 1}})
			} else {
				//上一次的异常状态已经恢复，目前处理正常状态,stat=1
				c.Update(bsonQuery, bson.M{"$set": bson.M{"lw.$.t": int64(warnData.Date*1000000 + warnData.Time),
					"lw.$.stat": 0, "lw.$.count": 0, "lw.$.sid": warnData.SensorId}})
			}
		}
	} else {
		//没有记录，插入数据
		lw := LastWarningT{}
		lw.T = int64(warnData.Date*1000000 + warnData.Time)
		lw.Type = warnData.WarningType
		lw.Sid = warnData.SensorId
		lw.Cardid = warnData.CardId
		lw.Sn = warnData.SerialNum
		lw.Stat = 0
		lw.Count = 0

		c.Upsert(bson.M{"rid": warnData.Rid}, bson.M{"$push": bson.M{"lw": lw}})
	}
}

// 恢复最新状态中的报警标志
func (p *DBOperation) LastWarningRestore(warnData *TireWarningT, warningType ...int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	cStatistics := s.DB(p.dbName).C(CollectionTireWarningStatistics)

	var res LastWarningsT
	var bsonQuery bson.M
	var err error
	var lw *LastWarningT
	var iSt int

	for _, wt := range warningType {
		//查询设备最新的同类报警
		//bsonQuery = bson.M{"rid": warnData.Rid, "lw": bson.M{"$elemMatch": bson.M{"sid": warnData.SensorId, "type": wt, "stat": 0}}}
		//2020.06.01 修改为按照轮位来更新
		bsonQuery = bson.M{"rid": warnData.Rid, "lw": bson.M{"$elemMatch": bson.M{"cardid": warnData.CardId,
			"sn": warnData.SerialNum, "type": wt, "stat": 0}}}
		err = c.Find(bsonQuery).Select(bson.M{"_id": 0, "lw.$": 1}).One(&res)

		if err == nil {
			if len(res.Lws) > 0 {
				lw = &(res.Lws[0])
				//当前为异常状态
				//保存纪录到报警统计表中
				tws := make(map[string]interface{})
				iSt = int(lw.T % 1000000)
				tws["d"] = warnData.Date
				tws["st"] = iSt
				tws["et"] = warnData.Time
				tws["lt"] = calcDuration(iSt, warnData.Time)
				tws["ma"] = p.GetMileage(warnData.Rid, warnData.Date, iSt, warnData.Time)
				tws["t"] = time.Now().Unix()
				tws["rid"] = warnData.Rid
				tws["sid"] = warnData.SensorId
				tws["cardid"] = warnData.CardId
				tws["sn"] = warnData.SerialNum
				tws["wt"] = wt
				tws["count"] = lw.Count
				cStatistics.Insert(tws)

				//更新最新状态
				c.Update(bsonQuery, bson.M{"$set": bson.M{"lw.$.stat": 1, "lw.$.sid": warnData.SensorId}})
			}
		}
	}
}

type LocationT struct {
	Lat float64 `json:"lat"`
	Lng float64 `json:"lng"`
}

// 计算某个时间段内的里程
func (p *DBOperation) GetMileage(rid string, date int, startTime, endTime int) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionPositions)
	bsonDates := make([]bson.M, 0)
	bsonDates = append(bsonDates, bson.M{"time": bson.M{"$gte": startTime}})
	bsonDates = append(bsonDates, bson.M{"time": bson.M{"$lte": endTime}})
	bsonQuery := bson.M{"rid": rid, "date": date, "$and": bsonDates}
	var res []LocationT

	err := c.Find(bsonQuery).Select(bson.M{"_id": 0, "lat": 1, "lng": 1}).Sort("time").All(&res)
	if err != nil {
		return 0
	}

	var g gps.GPS
	mileage := 0.0
	if len(res) == 0 {
		return 0
	}

	var lastLat, lastLng float64
	for _, v := range res {
		if lastLat == 0.0 && lastLng == 0.0 {
			lastLat, lastLng = v.Lat, v.Lng
		} else {
			mileage += g.Distance(v.Lat, v.Lng, lastLat, lastLng)
			lastLat, lastLng = v.Lat, v.Lng
		}
	}

	return int(mileage)
}

// 查询指定轮位某个报警没有处理的最新纪录，返回纪录时间
func (p *DBOperation) GetLastWarningByPosition(rid string, cardid, sn, wt int) int64 {
	type LastWarningT struct {
		LW []struct {
			T    int64 `bson:"t"`
			Stat int   `bson:"stat"`
		} `bson:"lw"`
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	var lw LastWarningT
	err := c.Find(bson.M{"rid": rid, "lw": bson.M{"$elemMatch": bson.M{"cardid": cardid, "sn": sn, "type": wt}}}).
		Select(bson.M{"_id": 0, "lw.$": 1}).One(&lw)
	if err != nil {
		return 0
	}
	if len(lw.LW) > 0 {
		if lw.LW[0].Stat == WarningStatusDone {
			return 0
		} else {
			t := lw.LW[0].T
			return intTimeToTimestamp(t)
		}
	}

	return 0
}

// 查询指定轮位的最新温度
func (p *DBOperation) GetLastTemperatureByPosition(rid string, cardid, sn int) int {
	type LastTemperatureT struct {
		LP []struct {
			Temp int `bson:"temp"`
		} `bson:"lp"`
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	var lp LastTemperatureT
	err := c.Find(bson.M{"rid": rid, "lp": bson.M{"$elemMatch": bson.M{"cardid": cardid, "sn": sn}}}).
		Select(bson.M{"_id": 0, "lp.$": 1}).One(&lp)
	if err != nil {
		return 0
	}
	if len(lp.LP) > 0 {
		return lp.LP[0].Temp
	}

	return 0
}

// 查询不同类型的报警间隔，默认返回1800秒，即半个小时
func (p *DBOperation) RewarnInterval(wt int) int {
	s := p.session.Copy()
	defer s.Close()

	var v map[string]int
	c := s.DB(p.dbName).C(CollectionWarningTypes)
	err := c.Find(bson.M{"wid": wt}).Select(bson.M{"_id": 0, "inter": 1}).One(&v)
	if err != nil {
		return 1800
	}

	return v["inter"]
}

// 把所有某个传感器某个指定报警类别的未完成纪录，设置为无效纪录
func (p *DBOperation) SetInvalid(sid string, wt int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)
	c.UpdateAll(bson.M{"sid": sid, "wt": wt, "stat": WarningStatusNew}, bson.M{"$set": bson.M{"stat": WarningStatusInvalid}})
}

func (p *DBOperation) SetInvalidByPosition(rid string, cardid, sn int, wt int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)
	c.UpdateAll(bson.M{"rid": rid, "cardid": cardid, "sn": sn, "wt": wt, "stat": WarningStatusNew},
		bson.M{"$set": bson.M{"stat": WarningStatusInvalid}})
}

func (p *TireWarningT) fromTireDataRaw(data *TireDataRawT) {
	var g gps.GPS
	var lat, lng float64

	p.Rid = data.Rid
	p.Oid = data._id
	p.T = data.T
	p.Date = data.Date
	p.Time = data.Time
	p.Latitude = data.Latitude
	p.Longitude = data.Longitude

	lat, lng = g.TransformFromWGSToGCJ(float64(p.Latitude), float64(p.Longitude))
	p.LatitudeG, p.LongitudeG = float32(lat), float32(lng)
	lat, lng = g.BDEncrypt(lat, lng)
	p.LatitudeB, p.LongitudeB = float32(lat), float32(lng)
}

func (p *TireWarningT) fromTireData(data *protocol808.TireData_t) {
	p.SensorId = data.SensorId
	p.CardId = data.CardId
	p.SerialNum = data.SerialNum
	p.Voltage = data.Voltage
	p.Temperature = data.Temperature
	p.Presure = data.Presure
}

// 获取接收器状态
func (p *DBOperation) ReceiverStatus(rid string) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	var res map[string]int

	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "status": 1}).One(&res)
	if err != nil {
		return 0
	}
	return res["status"]
}

// 处理异常工作时间
type LastWarningStatusT struct {
	LastTime int64 `bson:"t"`
	Warn     int   `bson:"warn"`
}

func (p *DBOperation) dealWarningTime(rid string, date, time int, haveWarning bool) {
	type LastStatusT struct {
		LastWarning LastWarningStatusT `bson:"lws"`
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	var res LastStatusT

	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "lws": 1}).One(&res)
	if err == nil {
		newTime := int64(date*1000000 + time)
		if newTime > res.LastWarning.LastTime {
			if res.LastWarning.Warn == 1 && haveWarning {
				dur := intTimeToDuration(int(res.LastWarning.LastTime), int(newTime))
				if dur > 0 {
					p.saveWarningTime(rid, date, dur)
				}
			}
			res.LastWarning.LastTime = newTime
			if haveWarning {
				res.LastWarning.Warn = 1
			} else {
				res.LastWarning.Warn = 0
			}
			c.Update(bson.M{"rid": rid}, bson.M{"$set": bson.M{"lws": res.LastWarning}})
		}
	}
}

// 累计异常时长
func (p *DBOperation) saveWarningTime(rid string, date int, warningTime int) {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionTimeStatistics)
	y := date / 10000
	m := date % 10000 / 100
	d := date % 100
	err := c.Find(bson.M{"rid": rid, "date": date}).Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		c.Update(bson.M{"rid": rid, "date": date}, bson.M{"$inc": bson.M{"awt": warningTime}})
	} else {
		//没有记录，则新增
		c.Insert(bson.M{"rid": rid, "date": date, "y": y, "m": m, "d": d, "awt": warningTime})
	}
}

// 读取设备的关联关系
func (p *DBOperation) getRelation(rid string) *RidRelationsT {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRelations)
	var rrs RidRelationsT

	c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 1, "rid": 1, "sid": 1, "cardid": 1, "sn": 1}).Sort("cardid", "sn").All(&(rrs.relations))
	return &rrs
}

// 重新处理轮位信息
func (p *DBOperation) refreshTirePosition(rid string, rrs []RidRelationT) {
	s := p.session.Copy()
	defer s.Close()

	cRelation := s.DB(p.dbName).C(CollectionRelations)
	cLastStatus := s.DB(p.dbName).C(CollectionLastStatuses)

	for _, v := range rrs {
		if v.ID == "" {
			//新增或更新
			//cRelation.Insert(bson.M{"rid": rid, "sid": v.Sid, "cardid": v.CardId, "sn": v.SN})
			cRelation.Upsert(bson.M{"rid": rid, "cardid": v.CardId, "sn": v.SN}, bson.M{"$set": bson.M{"sid": v.Sid}})
		} else if !v.KeepIt {
			//删除关联关系
			//cRelation.Remove(bson.M{"_id": v.ID})
			//2020.11.01 将SID设置为空，其它字段如胎号等不删除
			cRelation.Update(bson.M{"_id": v.ID}, bson.M{"$set": bson.M{"sid": ""}})
			//删除最新状态表中的胎温胎压数据
			cLastStatus.Update(bson.M{"rid": rid},
				bson.M{"$pull": bson.M{"lp": bson.M{"cardid": v.CardId, "sn": v.SN}, "lw": bson.M{"cardid": v.CardId, "sn": v.SN}}})
		}
	}
}

func (p *DBOperation) SaveReceiverWarning(warnData *TireWarningT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceiverWarnings)
	field := fmt.Sprintf("%d", warnData.WarningType)
	bsonQuery := bson.M{"date": warnData.Date, "rid": warnData.Rid}
	receiverInfo := p.getReceiverInfo(warnData.Rid)
	if receiverInfo == nil {
		return
	}

	err := c.Find(bsonQuery).Select(bson.M{"_id": 1}).One(nil)
	if err != nil {
		c.Insert(bson.M{"cid": receiverInfo.Cid, "tids": receiverInfo.Tids, "date": warnData.Date, "ft": warnData.Time,
			"lt": warnData.Time, "rid": warnData.Rid, "plate": receiverInfo.Plate, "wc": 1, "ws": bson.M{field: 1}})
	} else {
		c.Update(bsonQuery, bson.M{"$set": bson.M{"cid": receiverInfo.Cid, "tids": receiverInfo.Tids,
			"plate": receiverInfo.Plate, "lt": warnData.Time}, "$inc": bson.M{"wc": 1, "ws." + field: 1}})
	}
}

type ReceiverInfoT struct {
	Cid   int      `bson:"cid"`
	Tids  []string `bson:"tids"`
	Plate string   `bson:"plate"`
}

func (p *DBOperation) getReceiverInfo(rid string) *ReceiverInfoT {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	var ri ReceiverInfoT

	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "cid": 1, "tids": 1, "plate": 1}).One(&ri)
	if err != nil {
		return nil
	}

	return &ri
}

type ReceiverThresholdT struct {
	Type      int `bson:"type" json:"type"`
	Threshold struct {
		Pressure    [5][2]float32 `bson:"pres" json:"pressure"`
		Temperature int           `bson:"temp" json:"temperature"`
	} `bson:"threshold" json:"threshold"`
}

func (p *DBOperation) receiverThreshold(rid string) (*ReceiverThresholdT, error) {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionReceivers)

	var rt ReceiverThresholdT
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "rid": 1, "type": 1, "threshold": 1}).One(&rt)
	return &rt, err
}
